package com.qys.training.biz.file.service.impl;

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.qys.training.base.config.Font;
import com.qys.training.base.config.PDFTextConfig;
import com.qys.training.base.enumerate.BizCodeEnum;
import com.qys.training.base.exception.QysException;
import com.qys.training.base.util.BaseUtils;
import com.qys.training.base.util.FileUtils;
import com.qys.training.base.util.addTextUtils;
import com.qys.training.biz.file.criteria.FileInfoCriteria;
import com.qys.training.biz.file.entity.FileInfo;
import com.qys.training.biz.file.mapper.FileInfoMapper;
import com.qys.training.biz.file.service.FileInfoService;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Transactional
public class FileInfoServiceImpl implements FileInfoService {

    @Value("${qys.file.storage.path}")
    private String uploadPath;
    @Value("${qys.file.storage.path.outPdf}")
    private String outPdf;
    //@Value("${qys.font.storage.path}")
    private String fontPath="static/fonts/";

    public static final Logger logger = LoggerFactory.getLogger(FileInfoServiceImpl.class);

    private static final int MAX_FILE_SIZE = 10 * 1024 * 1024;

    @Autowired
    private FileInfoMapper fileInfoMapper;

    /**
     * 获取元数据完成存储
     * @param file
     * @return
     */
    private FileInfo getMetadata(MultipartFile file) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd/");
        String timePath = sdf.format(new Date());//按照格式化时间记名存储
        Long fileLength = file.getSize();
        logger.info("文件长度"+fileLength);
        if(MAX_FILE_SIZE < fileLength) {// 限制文件大小
            throw new QysException(BizCodeEnum.ERROR.getCode(),"文件大小超出限制（"+MAX_FILE_SIZE+"b)");
        }
        String originalFileName = file.getOriginalFilename();//文件原名
        logger.info(originalFileName);
        String suffix = originalFileName.substring(originalFileName.lastIndexOf(".")); //后缀用于限定上传格式
        if(!".pdf".equals(suffix)) {
            throw new QysException(BizCodeEnum.ERROR.getCode(),"文件格式必须是pdf哦");
        }
        String uuidName = BaseUtils.getUuid();
        String fileOnlyName = uuidName + suffix;
        String finalPath = uploadPath + timePath + fileOnlyName;
        File dest = FileUtils.uploadFile(file,finalPath);
        FileInfo info = new FileInfo();
        info.setFileName(originalFileName);//方便数据库中查看
        info.setLength(fileLength);
        info.setDigest(BaseUtils.fileToMD5(dest));
        info.setPath(timePath + fileOnlyName);
        return info;
    }

    public Long create(MultipartFile file) {
        FileInfo info = this.getMetadata(file);
        info.setCreateTime(new Date());
        fileInfoMapper.insert(info);
        return info.getId();
    }

    public void update(Long id, MultipartFile file) {
        FileInfo oldInfo = fileInfoMapper.get(id);
        String oldPath = oldInfo.getPath();

        //删除文件
        File oldFile = new File(uploadPath + oldPath);
        oldFile.delete();

        FileInfo newInfo = this.getMetadata(file);
        newInfo.setUpdateTime(new Date());
        newInfo.setCreateTime(oldInfo.getCreateTime());
        newInfo.setId(oldInfo.getId());
        fileInfoMapper.update(newInfo);
    }

    public void downloadById(HttpServletRequest request, HttpServletResponse response, Long id) {
        FileInfo info = fileInfoMapper.get(id);
        File file = new File(uploadPath +info.getPath());
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/octet-stream");
        FileInputStream fis = null;
        logger.info(info.getFileName());
        try {
            fis = new FileInputStream(file);
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(info.getFileName(), "utf-8"));
            IOUtils.copy(fis, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            throw new QysException(BizCodeEnum.UNKNOWN_ERROR.getCode(), null);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new QysException(BizCodeEnum.UNKNOWN_ERROR.getCode(), null);
                }
            }
        }

    }


    public void delete(Long id) {
        FileInfo oldInfo = fileInfoMapper.get(id);
        String oldPath = oldInfo.getPath();
        //删除文件
        File oldFile = new File(uploadPath +"/"+ oldPath);
        oldFile.delete();
        fileInfoMapper.delete(id);
    }


    public Map findList(FileInfoCriteria criteria) {
        int currentPage = criteria.getCurrentPage();
        int pageSize = criteria.getPageSize();
        criteria.setLimit( (currentPage-1) * pageSize );

        Integer count = fileInfoMapper.getCount(criteria);
        List fileInfoList = fileInfoMapper.getPage(criteria);
        Map<String,Object> result = new HashMap();
        result.put("total",count);
        result.put("elements",fileInfoList);
        return result;
    }

    public void downloadZip(HttpServletRequest request, HttpServletResponse response,List<Long> ids) throws IOException {
        List<FileInfo> infoList = fileInfoMapper.getListByIds(ids);

        response.setCharacterEncoding("utf-8");
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("download.zip", "utf-8"));
        OutputStream out  =response.getOutputStream();
        ZipOutputStream zos = null ;
        try {
            zos = new ZipOutputStream(out);
            for (int i = 0; i < infoList.size(); i++)  {
                FileInfo info = infoList.get(i);
                File srcFile = new File(uploadPath + info.getPath());
                byte[] buf = new byte[1024];
                zos.putNextEntry(new ZipEntry(i + info.getFileName()));
                int len;
                FileInputStream in = new FileInputStream(srcFile);
                while ((len = in.read(buf)) != -1){
                    zos.write(buf, 0, len);
                }
                zos.closeEntry();
                in.close();
            }
        } catch (Exception e) {
            throw new RuntimeException("error from ZipUtils",e);
        }finally{
            if(zos != null){
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    @Override
    public void addText(Long id, String text, float x, float y, Font font) {
        PDFTextConfig config = new PDFTextConfig();
        config.setText(text);
        config.setX(x);
        config.setY(y);
        config.setFont(font);
        config.setPageNum(1);

        FileInfo info = fileInfoMapper.get(id);
        String path = info.getPath();
        String originPath = uploadPath+path;

        PdfReader pdfReader = null;
        PdfStamper pdfStamper = null;
        try {
            pdfReader = new PdfReader(originPath);
            File pdfPath = new File(outPdf);
            if(!pdfPath.exists()){
                pdfPath.mkdir();
            }
            String path1=outPdf+info.getFileName();
            pdfStamper = new PdfStamper(pdfReader,new FileOutputStream(path1));
            String fontName = font.getDescription();
            String fontNewPath = fontPath+fontName;
            addTextUtils.addText(pdfStamper,config,fontNewPath);

            pdfReader.close();
            addTextUtils.overlayFile(outPdf+info.getFileName(),originPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



}
